package cn.sciento.export.filler;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import cn.sciento.export.ExcelFiller;
import cn.sciento.export.vo.ExportColumn;
import org.springframework.util.Assert;

public class SingleSheetFiller extends ExcelFiller {
    public static final String FILLER_TYPE = "single-sheet";
    private CellStyle oddTitleCellStyle;
    private CellStyle evenTitleCellStyle;
    private int currentSheetIndex;

    public SingleSheetFiller() {
    }

    public SingleSheetFiller(SXSSFWorkbook workbook) {
        super(workbook);
        this.setOddTitleCellStyle();
        this.setEventTitleCellStyle();
    }

    public String getFillerType() {
        return "single-sheet";
    }

    public void fillData(SXSSFWorkbook workbook, ExportColumn exportClass, List<?> data) {
        SXSSFSheet sheet = workbook.getSheetAt(this.currentSheetIndex++);
        sheet.setRandomAccessWindowSize(-1);
        this.fillData(sheet, exportClass, data);
    }

    private void fillData(SXSSFSheet sheet, ExportColumn exportClass, List<?> data) {
        int rows = 0;
        int i = 0;

        for (int len = data.size(); i < len; ++i) {
            Assert.isTrue(sheet.getLastRowNum() < 1000000, "export.too-many-data");
            SXSSFRow row = sheet.createRow(sheet.getLastRowNum() + 1);
            this.fillRow(row, exportClass.getExcelSheet().colOffset(), data.get(i), exportClass.getChildren());
            int count = this.fillChildren(sheet, data.get(i), row.getLastCellNum(), exportClass);

            for (int c = 1; c < count; ++c) {
                this.fillRow(sheet.getRow(row.getRowNum() + c), exportClass.getExcelSheet().colOffset(), data.get(i), exportClass.getChildren());
            }

            rows += count + 1;
            if (rows >= 100) {
                rows = 0;

                try {
                    sheet.flushRows(100);
                } catch (IOException var10) {
                    this.logger.error("flush rows error.", var10);
                }
            }
        }

    }

    private int fillChildren(SXSSFSheet sheet, Object data, int colOffset, ExportColumn exportClass) {
        int maxChildDataCount = 0;
        int lastRowNum = sheet.getLastRowNum();
        int rowIndex = lastRowNum;
        List<ExportColumn> exportColumns = this.getChildrenCheckedAndHasChild(exportClass);
        Iterator var9 = exportColumns.iterator();

        while (var9.hasNext()) {
            ExportColumn child = (ExportColumn) var9.next();
            List<Object> childData = this.getChildData(data, child);
            List<ExportColumn> childColumns = child.getChildren();
            int checkedCount = this.countChildrenChecked(child);
            int innerMaxChildCount = 0;

            for (int i = 0; i < childData.size(); ++i) {
                SXSSFRow row = null;
                row = sheet.getRow(rowIndex);
                if (row == null) {
                    row = sheet.createRow(rowIndex);
                }

                this.fillRow(row, colOffset, childData.get(i), childColumns);
                int childCount = this.fillChildren(sheet, childData.get(i), colOffset + checkedCount, child);

                for (int c = 1; c < childCount; ++c) {
                    this.fillRow(sheet.getRow(rowIndex + c), colOffset, childData.get(i), childColumns);
                }

                innerMaxChildCount += childCount > 0 ? childCount : 1;
                ++rowIndex;
            }

            rowIndex = lastRowNum;
            colOffset += checkedCount;
            if (innerMaxChildCount > maxChildDataCount) {
                maxChildDataCount = innerMaxChildCount;
            }
        }

        return maxChildDataCount;
    }

    public void createSheetAndTitle(SXSSFWorkbook workbook, ExportColumn exportClass) {
        List<ExportColumn> titleColumns = new LinkedList();
        this.collectAllTitleColumn(titleColumns, exportClass);
        String title = (String) StringUtils.defaultIfBlank(exportClass.getTitle(), exportClass.getName());
        SXSSFSheet sheet = workbook.createSheet(title);
        sheet.setDefaultColumnWidth(20);
        this.createTitleRow(sheet, exportClass.getExcelSheet().rowOffset(), exportClass.getExcelSheet().colOffset(), titleColumns);
    }

    private void collectAllTitleColumn(List<ExportColumn> titleColumns, ExportColumn exportClass) {
        if (exportClass.isChecked() && exportClass.hasChildren()) {
            titleColumns.add(exportClass);
            if (CollectionUtils.isNotEmpty(exportClass.getChildren())) {
                Iterator var3 = exportClass.getChildren().iterator();

                while (var3.hasNext()) {
                    ExportColumn ec = (ExportColumn) var3.next();
                    this.collectAllTitleColumn(titleColumns, ec);
                }
            }
        }

    }

    private void createTitleRow(SXSSFSheet sheet, int rowOffset, int colOffset, List<ExportColumn> titleColumns) {
        SXSSFRow titleRow = sheet.createRow(rowOffset);
        titleRow.setHeight((short) 350);
        CellStyle titleRowStyle = this.workbook.createCellStyle();
        titleRowStyle.setLocked(true);
        titleRow.setRowStyle(titleRowStyle);

        for (int i = 0; i < titleColumns.size(); ++i) {
            Iterator var8 = ((ExportColumn) titleColumns.get(i)).getChildren().iterator();

            while (var8.hasNext()) {
                ExportColumn column = (ExportColumn) var8.next();
                if (column.isChecked() && !column.hasChildren()) {
                    SXSSFCell cell = titleRow.createCell(colOffset);
                    this.fillCellValue(cell, column.getTitle(), Collections.emptyList(), column.getExcelColumn().pattern(), (List) null);
                    if (i % 2 == 0) {
                        cell.setCellStyle(this.oddTitleCellStyle);
                    } else {
                        cell.setCellStyle(this.evenTitleCellStyle);
                    }

                    this.setCellWidth(sheet, column.getType(), colOffset);
                    ++colOffset;
                }
            }
        }

    }

    private void fillRow(SXSSFRow row, int colOffset, Object rowData, List<ExportColumn> columns) {
        int cells = 0;
        Iterator var6 = columns.iterator();

        while (var6.hasNext()) {
            ExportColumn column = (ExportColumn) var6.next();
            if (column.isChecked() && !column.hasChildren()) {
                Object cellValue = null;

                try {
                    cellValue = FieldUtils.readField(rowData, column.getName(), true);
                } catch (Exception var10) {
                    this.logger.error("get value error.", var10);
                }

                SXSSFCell cell = row.createCell(colOffset + cells);
                this.fillCellValue(cell, cellValue, rowData, column.getExcelColumn().pattern(), Arrays.asList(column.getExcelColumn().renderers()));
                ++cells;
            }
        }

    }

    private List<ExportColumn> getChildrenCheckedAndHasChild(ExportColumn root) {
        return root != null && CollectionUtils.isNotEmpty(root.getChildren()) ? (List) root.getChildren().stream().filter((column) -> {
            return column.isChecked() && column.hasChildren();
        }).collect(Collectors.toList()) : Collections.emptyList();
    }

    private int countChildrenChecked(ExportColumn root) {
        if (root != null && CollectionUtils.isNotEmpty(root.getChildren())) {
            long count = root.getChildren().stream().filter((column) -> {
                return column.isChecked() && !column.hasChildren();
            }).count();
            return Integer.parseInt(String.valueOf(count));
        } else {
            return 0;
        }
    }

    private List<Object> getChildData(Object data, ExportColumn child) {
        String getter = "get" + child.getName();
        Method[] methods = data.getClass().getDeclaredMethods();
        Method[] var5 = methods;
        int var6 = methods.length;

        for (int var7 = 0; var7 < var6; ++var7) {
            Method method = var5[var7];
            if (method.getName().equalsIgnoreCase(getter)) {
                try {
                    method.setAccessible(true);
                    return (List) method.invoke(data) == null ? Collections.emptyList() : (List) method.invoke(data);
                } catch (Exception var10) {
                    this.logger.error("get child data error.", var10);
                }
            }
        }

        return Collections.emptyList();
    }

    private void setOddTitleCellStyle() {
        Font font = this.workbook.createFont();
        font.setColor((short) 32767);
        font.setBold(true);
        this.oddTitleCellStyle = this.workbook.createCellStyle();
        this.oddTitleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
        this.oddTitleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        this.oddTitleCellStyle.setFont(font);
        this.oddTitleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        this.oddTitleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        this.oddTitleCellStyle.setLocked(true);
    }

    private void setEventTitleCellStyle() {
        Font font = this.workbook.createFont();
        font.setColor((short) 32767);
        font.setBold(true);
        this.evenTitleCellStyle = this.workbook.createCellStyle();
        this.evenTitleCellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.index);
        this.evenTitleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        this.evenTitleCellStyle.setFont(font);
        this.evenTitleCellStyle.setAlignment(HorizontalAlignment.CENTER);
        this.evenTitleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        this.oddTitleCellStyle.setLocked(true);
    }
}
